﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text.RegularExpressions;

namespace springProject.AdminFunctional
{
    public class KeywordAnalysis
    {
        private string _content;

        /// <summary>
        /// Класс содержит информацию о параметрах слова
        /// </summary>
        public class WordsParameres
        {
            public string Word;
            public int Count;
            public double rating;
        }

        /// <summary>
        /// Класс содержит информацию о весах тегов 
        /// </summary>
        public class AuthorityForTags
        {
            /// <summary>
            /// Инициализирует базовые значения
            /// </summary>
            public AuthorityForTags()
            {
                H1 = 1;
                H2 = 0.8;
                H3 = 0.6;
                B = 0.3;
                Strong = 0.3;
                I = 0.3;
                U = 0.3;
                Another = 0.1;

            }
            private bool verificationIsOk(double d)
            {
                if (d >= 0 && d <= 1)
                {
                    return true;
                }

                return false;
            }

            private double _H1;
            private double _H2;
            private double _H3;
            private double _B;
            private double _Strong;
            private double _I;
            private double _U;
            private double _Another;


            public double H1
            {
                get { return _H1; }
                set { if (verificationIsOk(value)) _H1 = value; }
            }
            public double H2
            {
                get { return _H2; }
                set { if (verificationIsOk(value)) _H2 = value; }
            }
            public double H3
            {
                get { return _H3; }
                set { if (verificationIsOk(value)) _H3 = value; }
            }
            public double B
            {
                get { return _B; }
                set { if (verificationIsOk(value)) _B = value; }
            }
            public double Strong
            {
                get { return _Strong; }
                set { if (verificationIsOk(value)) _Strong = value; }
            }
            public double I
            {
                get { return _I; }
                set { if (verificationIsOk(value)) _I = value; }
            }
            public double U
            {
                get { return _U; }
                set { if (verificationIsOk(value)) _U = value; }
            }
            
            /// <summary>
            /// Прочие теги
            /// </summary>
            public double Another
            {
                get { return _Another; }
                set { if (verificationIsOk(value)) _Another = value; }
            }
        }

        /// <summary>
        /// Все слова встречающиеся на странице
        /// </summary>
        public IEnumerable<WordsParameres> AllWords { get; private set; }

        /// <summary>
        /// Слова встречающиеся в H1
        /// </summary>
        public IEnumerable<string> H1Words { get; private set; }

        /// <summary>
        /// Слова встречающиеся в H2
        /// </summary>
        public IEnumerable<string> H2Words { get; private set; }

        /// <summary>
        /// Слова встречающиеся в H3
        /// </summary>
        public IEnumerable<string> H3Words { get; private set; }

        /// <summary>
        /// Слова встречающиеся в b
        /// </summary>
        public IEnumerable<string> BWords { get; private set; }

        /// <summary>
        /// Слова встречающиеся в strong
        /// </summary>
        public IEnumerable<string> StrongWords { get; private set; }

        /// <summary>
        /// Слова встречающиеся в i
        /// </summary>
        public IEnumerable<string> IWords { get; private set; }

        /// <summary>
        /// Слова встречающиеся в u
        /// </summary>
        public IEnumerable<string> UWords { get; private set; }

        private AuthorityForTags _AuthoritiesForTags;
        /// <summary>
        /// Содержит информацию о весах для тегов. Используется для расчета рейтинга ключевых слов.
        /// </summary>
        public AuthorityForTags AuthoritiesForTags
        {
            get
            {
                return _AuthoritiesForTags;
            }
            set
            {
                _AuthoritiesForTags = value;
                SetRatingForWords();
            }
        }

        /// <summary>
        /// Возвращает коллекцию слов контента с параметрами
        /// </summary>
        private IEnumerable<WordsParameres> SetAllWords(string content)
        {
            string pattern = @"<.+?>"; //All tags
            Regex theRegex = new Regex(pattern, RegexOptions.Multiline);
            string text = theRegex.Replace(content, ""); //text without tags

            IEnumerable<string> words = text.Split(' ').Where(x => x != "").Select(x => x.ToLower());

            var uniqueWords = words.Union(words);

            var result = new List<WordsParameres>();
            foreach (var item in uniqueWords)
            {
                var temp = new WordsParameres();
                temp.Word = item;
                temp.Count = words.Where(x => x == item).Count();
                temp.rating = 0;
                result.Add(temp);
            }

            return result;
        }

        /// <summary>
        /// Возвращает коллекцию слов для заданного тега по переданному контенту
        /// </summary>
        private IEnumerable<string> SetTagWords(string content, string tagName)
        {
            string patternFindTag = @"(?<=<" + tagName + @">).*?(?=</" + tagName + @">)"; ; //All FindTag-texts
            string patternAllTags = @"<.+?>"; //All tags
            Regex theRegexFindTag = new Regex(patternFindTag, RegexOptions.IgnoreCase);
            Regex theRegexAllTags = new Regex(patternAllTags, RegexOptions.IgnoreCase);
            var FindTag = theRegexFindTag.Matches(content);//find all findTag-texts

            List<string> findTagWords = new List<string>();
            foreach (var item in FindTag)
            {
                //delete unnecessary tags and splin by space
                IEnumerable<string> temp = theRegexAllTags.Replace(item.ToString(), "").Split(' ').Where(x => x != "");
                foreach (var word in temp)
                {
                    findTagWords.Add(word);
                }
            }

            return findTagWords.Union(findTagWords);
        }

        /// <summary>
        /// Конструктор. Принимает контент обрабатываемой сраницы и инициализирует класс.
        /// </summary>
        /// <param name="content"></param>
        public KeywordAnalysis(string content)
        {
            _content = content;
            AllWords = SetAllWords(content);
            H1Words = SetTagWords(content, "h1");
            H2Words = SetTagWords(content, "h2");
            H3Words = SetTagWords(content, "h3");
            BWords = SetTagWords(content, "b");
            StrongWords = SetTagWords(content, "strong");
            IWords = SetTagWords(content, "i");
            UWords = SetTagWords(content, "u");

            AuthoritiesForTags = new AuthorityForTags();

            SetRatingForWords();
        }

        /// <summary>
        /// Расчитывает рейтинги слов
        /// </summary>
        private void SetRatingForWords()
        {
            List<WordsParameres> words = AllWords.ToList();

            // Расчитываем рейтинги кажого слова 
            for (int index = 0; index < words.Count; index++)
            {
                double h1 = H1Words.Contains(words[index].Word) ? AuthoritiesForTags.H1 : 0.0;
                double h2 = H2Words.Contains(words[index].Word) ? AuthoritiesForTags.H2 : 0.0;
                double h3 = H3Words.Contains(words[index].Word) ? AuthoritiesForTags.H3 : 0.0;
                double b = BWords.Contains(words[index].Word) ? AuthoritiesForTags.B : 0.0;
                double Strong = StrongWords.Contains(words[index].Word) ? AuthoritiesForTags.Strong : 0.0;
                double i = IWords.Contains(words[index].Word) ? AuthoritiesForTags.I : 0.0;
                double u = UWords.Contains(words[index].Word) ? AuthoritiesForTags.U : 0.0;

                words[index].rating = words[index].Count * (h1 + h2 + h3 + b + Strong + i + u + AuthoritiesForTags.Another);     
            }

            double sumRating = words.Sum(x => x.rating); //Суммарный рейтинг

            //Переводим ретинги в процентное соотношение от суммарного рейтинга страницы
            for (int index = 0; index < words.Count; index++)
            {
                words[index].rating = words[index].rating / sumRating;
            }
        }
    }
}